package com.nlscan.ncomgateway.core.data.backup

import android.util.Log
import com.nlscan.ncomgateway.core.data.preference.SettingsPreferenceManager
import java.lang.reflect.Modifier

/**
 * <pre>
 *  author: lin.qing
 *  time  : 2025/2/10
 *  desc  : 动态反射工具类
 * </pre>
 * 动态反射工具类 - 用于自动备份/恢复 SharedPreferences 配置项
 * 严格遵循以下规则：
 * 1. KEY_ABOUT 等没有对应 getter 的常量过滤
 * 2. 类型推断规则：
 *    - Int: 仅 KEY_OUTPUT_MODE
 *    - Boolean: KEY_IP_DATA_FORMAT_SWITCH, KEY_IP_DATA_FORMAT_USE_PACKET_HEADER, KEY_AUTO_HIDE_AFTER_PAIRING, KEY_LAUNCH_APP_AFTER_PAIRING
 *    - String: 其余所有有效字段
 * 3. 特殊方法名映射：
 *    - isIpDataFormatOpen -> getIpDataFormatSwitch
 *    - isIpDataFormatUsePacketHeader -> getIpDataFormatUsePacketHeader
 */
object PreferenceReflector {
    private const val TAG = "PreferenceReflector"
    private const val KEY_PREFIX = "KEY_"
    private const val GETTER_PREFIX = "get"
    private const val SETTER_PREFIX = "set"

    // 特殊方法名映射表
    /**
     * 两种场景
     * 1）不全， "getBrOutputAction" to "getBroadcastOutputAction",
     * 2）is开头： "getIpDataFormatSwitch" to "isIpDataFormatOpen",
     */
    private val methodNameMappings = mapOf(
        "getIpDfSwitch" to "isIpDataFormatOpen",
        "setIpDfSwitch" to "setIpDataFormatOpen",
        "getIpDfUsePkgHead" to "isIpDataFormatUsePacketHeader",
        "setIpDfUsePkgHead" to "setIpDataFormatUsePacketHeader",
        "getAutoHideAfterPairing" to "isAutoHideAfterPairing",
        "getLaunchAppAfterPairing" to "isLaunchAppAfterPairing",

        "getBrOutputAction" to "getBroadcastOutputAction",
        "setBrOutputAction" to "setBroadcastOutputAction",
        "getBrOutputExtraResult1" to "getBroadcastOutputExtraResult",
        "setBrOutputExtraResult1" to "setBroadcastOutputExtraResult",
        "getBrOutputExtraDevName" to "getBroadcastOutputExtraDeviceName",
        "setBrOutputExtraDevName" to "setBroadcastOutputExtraDeviceName",
        "getBrOutputExtraAddress" to "getBroadcastOutputExtraAddress",
        "setBrOutputExtraAddress" to "setBroadcastOutputExtraAddress",
        "getBrOutputExtraSerialNumber" to "getBroadcastOutputExtraSerialNumber",
        "setBrOutputExtraSerialNumber" to "setBroadcastOutputExtraSerialNumber",
        "getBrOutputExtraBarcodeType" to "getBroadcastOutputExtraBarcodeType",
        "setBrOutputExtraBarcodeType" to "setBroadcastOutputExtraBarcodeType",
        "getBrOutputExtraBarcodeTypeName" to "getBroadcastOutputExtraBarcodeTypeName",
        "setBrOutputExtraBarcodeTypeName" to "setBroadcastOutputExtraBarcodeTypeName",

        "getDfPrefix" to "getDataFormatPrefix",
        "setDfPrefix" to "setDataFormatPrefix",
        "getDfSuffix" to "getDataFormatSuffix",
        "setDfSuffix" to "setDataFormatSuffix",
        "getDfFieldBarcode" to "getDataFormatBarcodeField",
        "setDfFieldBarcode" to "setDataFormatBarcodeField",
        "getDfFieldDevName" to "getDataFormatDeviceNameField",
        "setDfFieldDevName" to "setDataFormatDeviceNameField",
        "getDfFieldDevAddress" to "getDataFormatDeviceAddressField",
        "setDfFieldDevAddress" to "setDataFormatDeviceAddressField",
        "getDfFieldSerialNumber" to "getDataFormatSerialNumberField",
        "setDfFieldSerialNumber" to "setDataFormatSerialNumberField",
        "getDfFieldBarcodeType" to "getDataFormatBarcodeTypeField",
        "setDfFieldBarcodeType" to "setDataFormatBarcodeTypeField",
        "getDfFieldBarcodeTypeName" to "getDataFormatBarcodeTypeNameField",
        "setDfFieldBarcodeTypeName" to "setDataFormatBarcodeTypeNameField",
        "getDfFieldAssignor" to "getDataFormatFieldAssignor",
        "setDfFieldAssignor" to "setDataFormatFieldAssignor",
        "getDfFieldSeparator" to "getDataFormatFieldSeparator",
        "setDfFieldSeparator" to "setDataFormatFieldSeparator",

        "getIpOutputAddress" to "getIpOutputHostname",
        "setIpOutputAddress" to "setIpOutputHostname",
    )

    // 需要过滤的常量
    private val ignoredKeys = setOf(
        SettingsPreferenceManager.KEY_CONNECT_CODE_CONFIG,
        SettingsPreferenceManager.KEY_EMULATE_KEY_OUTPUT_SETTING,
        SettingsPreferenceManager.KEY_FILL_OUTPUT_SETTING,
        SettingsPreferenceManager.KEY_BROADCAST_OUTPUT_SETTING,
        SettingsPreferenceManager.KEY_IP_OUTPUT_SETTING,
        SettingsPreferenceManager.KEY_TCP_CONNECT_STATE,
        SettingsPreferenceManager.KEY_UDP_LOCAL_PORT_STATE,
        SettingsPreferenceManager.KEY_IP_DATA_FORMAT_SETTING,
        SettingsPreferenceManager.KEY_SCAN_PROMPT_SETTING,
        SettingsPreferenceManager.KEY_PREFIX_SUFFIX,
        SettingsPreferenceManager.KEY_DATA_EDIT,
        SettingsPreferenceManager.KEY_SELECT_LAUNCH_APP,
        SettingsPreferenceManager.KEY_ONE_CLICK_UNBINDING,
        SettingsPreferenceManager.KEY_PWD_PROTECT,
        SettingsPreferenceManager.KEY_BACKUP_RECOVERY,
        SettingsPreferenceManager.KEY_ABOUT,
        //虚拟键盘无权限改，暂不处理
        SettingsPreferenceManager.KEY_SHOW_IME
    )

    // 有效 KEY 集合
    private val validKeys by lazy {
        SettingsPreferenceManager::class.java.declaredFields
            .filter { field ->
                field.name.startsWith(KEY_PREFIX) &&
                        Modifier.isStatic(field.modifiers) &&
                        Modifier.isFinal(field.modifiers) &&
                        !ignoredKeys.contains(field.get(null) as String)
//                        && hasGetter(field.name)
            }
            .map { it.get(null) as String }
            .toSet()
    }

    // 类型推断规则
    private enum class ValueType { STRING, INT, BOOLEAN }

    /* *************************
     *     公共接口方法
     ************************* */

    /**
     * 生成当前配置的完整快照
     */
    fun backupAllSettings(): Map<String, Any> {
        return validKeys.associateWith { key ->
            when (inferValueType(key)) {
                ValueType.INT -> getIntValue(key)
                ValueType.BOOLEAN -> getBooleanValue(key)
                else -> getStringValue(key)
            }
        }
    }

    /**
     * 从配置快照恢复设置
     */
    fun restoreAllSettings(config: Map<String, Any>) {
        config.forEach { (key, value) ->
            if (!validKeys.contains(key)) {
                Log.w(TAG, "跳过无效的配置项: $key")
                return@forEach
            }

            when (inferValueType(key)) {
                ValueType.INT -> setIntValue(key, value)
                ValueType.BOOLEAN -> setBooleanValue(key, value)
                else -> setStringValue(key, value)
            }
        }
    }

    /* *************************
     *     核心反射逻辑
     ************************* */

    // region 类型推断
    private fun inferValueType(key: String): ValueType {
        return when (key) {
            SettingsPreferenceManager.KEY_OUTPUT_MODE,
            SettingsPreferenceManager.KEY_ADD_DEVICE_LIMIT,
            SettingsPreferenceManager.KEY_EXCEED_DEVICE_LIMIT_HANDLE,
            SettingsPreferenceManager.KEY_CONNECT_CODE_TYPE -> ValueType.INT

            SettingsPreferenceManager.KEY_IP_DATA_FORMAT_SWITCH,
            SettingsPreferenceManager.KEY_IP_DATA_FORMAT_USE_PACKET_HEADER,
            SettingsPreferenceManager.KEY_AUTO_HIDE_AFTER_PAIRING,
            SettingsPreferenceManager.KEY_LAUNCH_APP_AFTER_PAIRING -> ValueType.BOOLEAN

            else -> ValueType.STRING
        }
    }
    // endregion

    // region Getter 反射
    private fun getStringValue(key: String): String {
//        Log.i(TAG,"getStringValue")
        return tryInvokeMethod<String>(key, GETTER_PREFIX) ?: ""
    }

    private fun getIntValue(key: String): Int {
//        Log.i(TAG,"getIntValue")
        return tryInvokeMethod<Int>(key, GETTER_PREFIX) ?: 0
    }

    private fun getBooleanValue(key: String): Boolean {
//        Log.i(TAG,"getBooleanValue")
        return tryInvokeMethod<Boolean>(key, GETTER_PREFIX) ?: false
    }
    // endregion

    // region Setter 反射
    private fun setStringValue(key: String, value: Any) {
        tryInvokeMethod<Unit>(key, SETTER_PREFIX, value.toString())
    }

    private fun setIntValue(key: String, value: Any) {
        val intValue = value.toString().toIntOrNull() ?: 0
        tryInvokeMethod<Unit>(key, SETTER_PREFIX, intValue)
    }

    private fun setBooleanValue(key: String, value: Any) {
        val boolValue = value.toString().toBooleanStrictOrNull() ?: false
        tryInvokeMethod<Unit>(key, SETTER_PREFIX, boolValue)
    }
    // endregion

    // region 反射工具方法
    @Suppress("UNCHECKED_CAST")
    private inline fun <reified T> tryInvokeMethod(
        key: String,
        prefix: String,
        vararg args: Any?
    ): T? {
        return try {
            val methodName = generateMethodName(key, prefix)
            //Log.e(TAG, "尝试的 methodName=$methodName")
            // 获取 SettingsPreferenceManager 单例实例
            val managerInstance = SettingsPreferenceManager
            val method = SettingsPreferenceManager::class.java
                .declaredMethods
                .firstOrNull { it.name == methodName }
                ?: throw NoSuchMethodException("Method $methodName not found")

            when {
                //[fix]报错 java.lang.NullPointerException: null receiver 表示在反射调用时，方法需要 实例对象 作为接收者，但实际传入了 null。尽管 getOutputMode() 方法存在，但由于 SettingsPreferenceManager 是 Kotlin object 单例类，反射调用时需通过实例访问。
//                method.parameterTypes.isEmpty() -> method.invoke(null) as? T
//                else -> method.invoke(null, *args) as? T
                method.parameterTypes.isEmpty() ->
                    method.invoke(managerInstance) as? T // 传入实例
                else ->
                    method.invoke(managerInstance, *args) as? T
            }
        } catch (e: Exception) {
            Log.e(TAG, "反射调用失败 [key=$key, methodPrefix=$prefix], 尝试的 methodName=$", e)
            null
        }
    }

    private fun generateMethodName(key: String, prefix: String): String {
        //[fix]key 是小写 KEY_OUTPUT_MODE = "key_output_mode"  getOutputMode
        //KEY_PREFIX 对应的是 大写的 KEY_ ,不匹配
        //val rawKey = key.removePrefix(KEY_PREFIX)
        val rawKey = key.removePrefix("key_")
        val normalizedKey = rawKey.split('_')
            .joinToString("") { it.capitalize() }

        return methodNameMappings["$prefix$normalizedKey"] ?: "$prefix$normalizedKey"
    }

    private fun hasGetter(fieldName: String): Boolean {
        val key = fieldName.removePrefix(KEY_PREFIX)
        val getterName = generateMethodName(fieldName, GETTER_PREFIX)
        return SettingsPreferenceManager::class.java.declaredMethods
            .any { method ->
                method.name == getterName &&
                        Modifier.isPublic(method.modifiers) &&
                        method.parameterTypes.isEmpty()
            }
    }
    // endregion
}